﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Xml.Serialization;

namespace Microsoft.WowAddonStudio.FrameXml.Serialization
{
    [Serializable]
    [DesignerCategory("code")]
    [XmlType(AnonymousType = true, Namespace = "http://www.blizzard.com/wow/ui/")]
    [DebuggerDisplay("X = {X}, Y = {Y}")]
    public class AbsDimension : SerializationObject, ICloneable, ICopiable<AbsDimension>, IEquatable<AbsDimension>
    {
        /// <summary>
        /// Gets or sets the value of X.
        /// </summary>
        [XmlAttribute("x")]
        public int X { get; set; }

        /// <summary>
        /// Gets or sets the value of Y.
        /// </summary>
        [XmlAttribute("y")]
        public int Y { get; set; }

        /// <summary>
        /// Converts the dimension to a <see cref="Size"/>.
        /// </summary>
        /// <returns>A <see cref="Size"/> structure.</returns>
        public Size ToSize()
        {
            return new Size(X, Y);
        }

        /// <summary>
        /// Converts the dimension to a <see cref="Point"/>.
        /// </summary>
        /// <param name="invertY">True, if the value of Y should be inverted.</param>
        /// <returns>A <see cref="Point"/> structure.</returns>
        public Point ToPoint(bool invertY)
        {
            return new Point(X, invertY ? -Y : Y);
        }

        /// <summary>
        /// Converts the dimension to a <see cref="Point"/> and inverts the Y coordinate.
        /// </summary>
        /// <returns>A <see cref="Point"/> structure.</returns>
        public Point ToPoint()
        {
            return this.ToPoint(true);
        }

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>The cloned instance.</returns>
        public object Clone()
        {
            return this.Copy();
        }

        /// <summary>
        /// Creates a new object that is a copy of the instance.
        /// </summary>
        /// <returns>The copied instance.</returns>
        /// <remarks>Performs a deep copy.</remarks>
        public AbsDimension Copy()
        {
            return new AbsDimension { X = X, Y = Y };
        }

        public bool Equals(AbsDimension other)
        {
            if (ReferenceEquals(null, other))
                return false;
            if (ReferenceEquals(this, other))
                return true;
            return other.X == X && other.Y == Y;
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">
        /// The <paramref name="obj"/> parameter is null.
        /// </exception>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
                return false;
            if (ReferenceEquals(this, obj))
                return true;
            if (obj.GetType() != typeof (AbsDimension))
                return false;
            return Equals((AbsDimension) obj);
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            unchecked
            {
                return (X*397) ^ Y;
            }
        }

        /// <summary>
		/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
		/// </returns>
    	public override string ToString()
    	{
			return String.Format("AbsDimension: [X = {0}, Y = {1}]", X, Y);
		}
    }
}